#coding=utf-8
import math

#[-2.96,-2.23,-3.37.-3.35] 2183.5 WX
#[0.55,0.71,-0.03,0.49,-6.15] 1633.8 WX+B

dataFileName = "F:\LR\LRTrainNew.txt"
DATA = []   #与原文档相同
#W = [1]*4   #当前参数
#W_NEW = []  #最新参数

#读取数据
def loadData():
    file = open(dataFileName,"r",encoding="GB2312")
    
    for lines in file.readlines():
        xi = []
        
        for v in lines.split(" "):
            xi.append(float(v))
        
        DATA.append(xi)
    
    file.close()
#    for i in range(len(DATA)):
#        print(str(DATA[i]))

#sigmoid
def sigmoid(W,X):
    wx = 0

    for i in range(len(W)):
        wx += W[i]*X[i+2]
    
#    print("-wx:" + str(-wx))
#    print("math.exp(-wx):" + str(math.exp(-wx)))
    s = 1.0 / (1 + math.exp(-wx))

    return s
    
#inner product
def innerProduct(X,Y):
    if len(X) != len(Y):
        return 0
		
    z = 0
    for i in range(len(X)):
        z += X[i] * Y[i]
    return z

#outer product
def outerProduct(X,Y):
    pass


#求模
def module(V):
    sum = 0
    for i in range(len(V)):
        sum += V[i] ** 2
        
    lenth = math.sqrt(sum)

    return lenth  

#归一化
def normalizing(V):
    sum = 0
    for i in range(len(V)):
        sum += V[i] ** 2
        
    lenth = math.sqrt(sum)
    
    for i in range(len(V)):
        V[i] /= lenth
        
    return V

#向量相加
def add(V1,V2):
    V = []
    for i in range(len(V1)):
#        print("i"+str(i))
#        print("len(V1)"+str(len(V1)))
#        print("len(V2)"+str(len(V2)))
        V.append(V1[i] + V2[i])
    
    return V
    

#向量乘以n倍
def nTimes(n,V):
    for i in range(len(V)):
        V[i] = n * V[i]
    
    return V
    
#负对数似然
def likelihood(W):
    global DATA
    
    l = 0
    
    for i in range(len(DATA)):
        s = sigmoid(W,DATA[i])
#        print("S:" + str(s))
        l += W[0] * math.log(s) + W[1] * math.log(1 - s)
        
    print("likelihood:" + str(l))
    return l

#梯度
def  gradient(W):
    global DATA
    
    G = [0] * 4
    
    for i in range(len(DATA)):
        s = sigmoid(W,DATA[i])
        
        times = DATA[i][1] * s - DATA[i][0] - s
        
        for j in range(len(G)):
            G[j] += times * DATA[i][j+2]
            
    print("gradient:" + str(G))
    
    return G

        
#hesian矩阵
def hesian():
    pass


#梯度下降法
def lineSearch():
    
    D = []      #梯度
    DIR = []    #搜索方向
    
    a = 0.5     #折半因子
    c = 0.1       #步长
    b = 0.5     #容许度
    
    max_k = 100
    
    k = 0
    
    W = [0] *4
    W_NEW = [0]

    fw = 0
    fwNew = 0
    
    gotIt = "NO"

    fw = likelihood(W)
    
    while True:
        k += 1
        print("Wave " + str(k) + " ...")
        
        D = gradient(W)

        DIR = D.copy()
        DIR = nTimes(-1,DIR)
        DIR = normalizing(DIR)
        
        print("W:" +str(W))
        print("nTimes(c,DIR):" +str(nTimes(c,DIR)))
        W_NEW = add(W,nTimes(c,DIR))

        fwNew = likelihood(W_NEW)
        
        print("W:" + str(W))
        print("WNEW:" + str(W_NEW))
#        print("nTimes(-1,W):" + str(nTimes(-1,W)))
#        print("add(W_NEW,nTimes(-1,W)):" + str(add(W_NEW,nTimes(-1,W))))
#        print("innerProduct(D,add(W_NEW,nTimes(-1,W))):" + str(innerProduct(D,add(W_NEW,nTimes(-1,W)))))

        minDecrease = b * math.fabs((innerProduct(D,add(W_NEW,nTimes(-1,W)))))

#        print("minDecrease:" + str(minDecrease))
#        print("fw:" + str(fw))
#        print("fwNew:" + str(fwNew))
        
        if fw == fwNew or fw - fwNew > minDecrease:
            print("speed is out of tolerate, failed~")
            break

        if k > max_k:
            print("try over " + str(k) + "times, failed~")
            break
            
        W = W_NEW
        fw = fwNew
        c *= a
        
    print(W)

#        print("D:"+str(D))
#        DIR = D.copy()
#        print("DIR:"+str(DIR))
#        DIR = nTimes(-1,DIR)
#        print("DIR:"+str(DIR))
#        DIR = normalizing(DIR)
#        print("DIR:"+str(DIR))
#        print("D:"+str(D))




loadData()
lineSearch()